﻿//Unit.cs
//Copyright (c) 2013 StockSharp LLC, all rights reserved.
//This code module is part of StockSharp library.
//This code is licensed under the GNU GENERAL PUBLIC LICENSE Version 3.
//See the file License.txt for the license details.
//More info on: http://stocksharp.com

namespace StockSharp.BusinessEntities
{
	using System;
	using System.Linq;
	using System.Runtime.Serialization;

	using Ecng.Common;
	using Ecng.ComponentModel;
	using Ecng.Serialization;

	/// <summary>
	/// Единицы измерения.
	/// </summary>
	[Serializable]
	[System.Runtime.Serialization.DataContract]
	public enum UnitTypes
	{
		/// <summary>
		/// Абсолютное значение. Шаг изменения равен заданному числу.
		/// </summary>
		[EnumMember]
		Absolute,

		/// <summary>
		/// Проценты. Шаг изменения – одна сотая процента.
		/// </summary>
		[EnumMember]
		Percent,

		/// <summary>
		/// Пункт цены инструмента. Вычисляется на основе значения <see cref="Security.MinStepPrice"/>.
		/// </summary>
		[EnumMember]
		Point,

		/// <summary>
		/// Шаг цены инструмента. Вычисляется на основе значения <see cref="Security.MinStepSize"/>.
		/// </summary>
		[EnumMember]
		Step,

		/// <summary>
		/// Лимитированное значение. Данная единица изменения позволяет задавать конкретное число,
		/// которое не может быть использовано в арифметических операциях <see cref="Unit"/>.
		/// </summary>
		[EnumMember]
		Limit,
	}

	/// <summary>
	/// Специальный класс, позволяющий задавать величины в процентном, абсолютном, пунктовым и пипсовых значениях.
	/// </summary>
	[Serializable]
	[System.Runtime.Serialization.DataContract]
	[Ignore(FieldName = "IsDisposed")]
	public class Unit : Equatable<Unit>, IOperable<Unit>
	{
		/// <summary>
		/// Создать величину.
		/// </summary>
		public Unit()
		{
		}

		/// <summary>
		/// Создать абсолютную величину <see cref="UnitTypes.Absolute"/>.
		/// </summary>
		/// <param name="value">Значение.</param>
		public Unit(decimal value)
			: this(value, UnitTypes.Absolute)
		{
		}

		/// <summary>
		/// Создать величину типа <see cref="UnitTypes.Absolute"/> или <see cref="UnitTypes.Percent"/>.
		/// </summary>
		/// <param name="value">Значение.</param>
		/// <param name="type">Единица измерения.</param>
		public Unit(decimal value, UnitTypes type)
			: this(value, type, null)
		{
		}

		/// <summary>
		/// Создать величину типа <see cref="UnitTypes.Point"/> или <see cref="UnitTypes.Step"/>.
		/// </summary>
		/// <param name="value">Значение.</param>
		/// <param name="type">Единица измерения.</param>
		/// <param name="security">Информация по инструменту.</param>
		public Unit(decimal value, UnitTypes type, Security security)
		{
			// mika Данную проверку лучше делать при арифметических действиях
			//
			//if (type == UnitTypes.Point || type == UnitTypes.Step)
			//{
			//    if (security == null)
			//        throw new ArgumentException("Единица измерения не может быть '{0}' так как не передана информация об инструменте.".Put(type), "type");
			//}

			Value = value;
			Type = type;
			Security = security;
		}

		/// <summary>
		/// Единица измерения.
		/// </summary>
		[DataMember]
		public UnitTypes Type { get; set; }

		/// <summary>
		/// Значение.
		/// </summary>
		[DataMember]
		public decimal Value { get; set; }

		/// <summary>
		/// Информация по инструменту. Необходима при использовании <see cref="UnitTypes.Point"/> и <see cref="UnitTypes.Step"/>.
		/// </summary>
		[DataMember]
		[RelationSingle(IdentityType = typeof(string))]
		public Security Security { get; set; }

		///<summary>
		/// Создать копию объекта <see cref="Unit" />.
		///</summary>
		///<returns>Копия.</returns>
		public override Unit Clone()
		{
			return new Unit
			{
				Type = Type,
				Value = Value,
				Security = Security,
			};
		}

		/// <summary>
		/// Привести <see cref="decimal"/> значение к объекту <see cref="Unit"/>.
		/// </summary>
		/// <param name="value"><see cref="decimal"/> значение.</param>
		/// <returns>Объект <see cref="Unit"/>.</returns>
		public static implicit operator Unit(decimal value)
		{
			return new Unit(value);
		}

		/// <summary>
		/// Привести <see cref="int"/> значение к объекту <see cref="Unit"/>.
		/// </summary>
		/// <param name="value"><see cref="int"/> значение.</param>
		/// <returns>Объект <see cref="Unit"/>.</returns>
		public static implicit operator Unit(int value)
		{
			return new Unit(value);
		}

		/// <summary>
		/// Привести объект <see cref="Unit"/> к <see cref="decimal"/> значению.
		/// </summary>
		/// <param name="unit">Объект <see cref="Unit"/>.</param>
		/// <returns><see cref="decimal"/> значение.</returns>
		public static explicit operator decimal(Unit unit)
		{
			if (unit == null)
				throw new ArgumentNullException("unit");

			switch (unit.Type)
			{
				case UnitTypes.Limit:
				case UnitTypes.Absolute:
					return unit.Value;
				case UnitTypes.Percent:
					throw new ArgumentException("Невозможно привести процентное значение в абсолютное.", "unit");
				case UnitTypes.Point:
					return unit.Value * unit.GetStepPrice();
				case UnitTypes.Step:
					return unit.Value * unit.GetStepSize();
				default:
					throw new ArgumentOutOfRangeException("unit");
			}
		}

		/// <summary>
		/// Привести <see cref="double"/> значение к объекту <see cref="Unit"/>.
		/// </summary>
		/// <param name="value"><see cref="double"/> значение.</param>
		/// <returns>Объект <see cref="Unit"/>.</returns>
		public static implicit operator Unit(double value)
		{
			return (decimal)value;
		}

		/// <summary>
		/// Привести объект <see cref="Unit"/> к <see cref="double"/> значению.
		/// </summary>
		/// <param name="unit">Объект <see cref="Unit"/>.</param>
		/// <returns><see cref="double"/> значение.</returns>
		public static explicit operator double(Unit unit)
		{
			return (double)(decimal)unit;
		}

		///// <summary>
		///// Привести <see cref="string"/> значение к объекту <see cref="Unit"/>.
		///// </summary>
		///// <param name="value"><see cref="string"/> значение.</param>
		///// <returns>Объект <see cref="Unit"/>.</returns>
		//public static implicit operator Unit(string value)
		//{
		//    return value.ToUnit(null);
		//}

		private static Unit CreateResult(Unit u1, Unit u2, Func<decimal, decimal, decimal> operation, Func<decimal, decimal, decimal> percentOperation)
		{
			//  предовратить вызов переопределенного оператора
			//if (u1 == null)
			if (u1.IsNull())
				throw new ArgumentNullException("u1");

			//if (u2 == null)
			if (u2.IsNull())
				throw new ArgumentNullException("u2");

			if (u1.Type == UnitTypes.Limit || u2.Type == UnitTypes.Limit)
				throw new ArgumentException("Лимитированное значение не может участвовать в арифметических операциях.");

			if (operation == null)
				throw new ArgumentNullException("operation");

			if (percentOperation == null)
				throw new ArgumentNullException("percentOperation");

			if (u1.Security != null && u2.Security != null && u1.Security != u2.Security)
				throw new ArgumentException("Несовпадение инструментов {0} и {1}.".Put(u1.Security.Id, u2.Security.Id));

			var result = new Unit
			{
				Type = u1.Type,
				Security = u1.Security ?? u2.Security
			};

			if (u1.Type == u2.Type)
			{
				result.Value = operation(u1.Value, u2.Value);
			}
			else
			{
				if (u1.Type == UnitTypes.Percent || u2.Type == UnitTypes.Percent)
				{
					result.Type = u1.Type == UnitTypes.Percent ? u2.Type : u1.Type;

					var nonPerValue = u1.Type == UnitTypes.Percent ? u2.Value : u1.Value;
					var perValue = u1.Type == UnitTypes.Percent ? u1.Value : u2.Value;

					result.Value = percentOperation(nonPerValue, perValue * nonPerValue.Abs() / 100.0m);
				}
				else
				{
					var value = operation((decimal)u1, (decimal)u2);

					switch (result.Type)
					{
						case UnitTypes.Absolute:
							break;
						case UnitTypes.Point:
							value /= u1.GetStepPrice(result.Security);
							break;
						case UnitTypes.Step:
							value /= u1.GetStepSize(result.Security);
							break;
						default:
							throw new ArgumentOutOfRangeException();
					}

					result.Value = value;
				}
			}

			return result;
		}

		/// <summary>
		/// Сложить два объекта <see cref="Unit"/>.
		/// </summary>
		/// <param name="u1">Первый объект <see cref="Unit"/>.</param>
		/// <param name="u2">Второй объект <see cref="Unit"/>.</param>
		/// <returns>Результат сложения.</returns>
		public static Unit operator +(Unit u1, Unit u2)
		{
			return CreateResult(u1, u2, (v1, v2) => v1 + v2, (nonPer, per) => nonPer + per);
		}

		/// <summary>
		/// Перемножить два объекта <see cref="Unit"/>.
		/// </summary>
		/// <param name="u1">Первый объект <see cref="Unit"/>.</param>
		/// <param name="u2">Второй объект <see cref="Unit"/>.</param>
		/// <returns>Результат перемножения.</returns>
		public static Unit operator *(Unit u1, Unit u2)
		{
			return CreateResult(u1, u2, (v1, v2) => v1 * v2, (nonPer, per) => nonPer * per);
		}

		/// <summary>
		/// Вычесть одну величину <see cref="Unit"/> из другой.
		/// </summary>
		/// <param name="u1">Первый объект <see cref="Unit"/>.</param>
		/// <param name="u2">Второй объект <see cref="Unit"/>.</param>
		/// <returns>Результат вычитания.</returns>
		public static Unit operator -(Unit u1, Unit u2)
		{
			return CreateResult(u1, u2, (v1, v2) => v1 - v2, (nonPer, per) => (u1.Type == UnitTypes.Percent ? (per - nonPer) : (nonPer - per)));
		}

		/// <summary>
		/// Поделить одну величину <see cref="Unit"/> на другую.
		/// </summary>
		/// <param name="u1">Первый объект <see cref="Unit"/>.</param>
		/// <param name="u2">Второй объект <see cref="Unit"/>.</param>
		/// <returns>Результат деления.</returns>
		public static Unit operator /(Unit u1, Unit u2)
		{
			return CreateResult(u1, u2, (v1, v2) => v1 / v2, (nonPer, per) => u1.Type == UnitTypes.Percent ? per / nonPer : nonPer / per);
		}

		/// <summary>
		/// Рассчитать хеш-код объекта <see cref="Unit"/>.
		/// </summary>
		/// <returns>Хеш-код.</returns>
		public override int GetHashCode()
		{
			return Type.GetHashCode() ^ Value.GetHashCode();
		}

		/// <summary>
		/// Сравнить величину на эквивалентность с другой.
		/// </summary>
		/// <param name="other">Другая величина, с которой необходимо сравнивать.</param>
		/// <returns>true, если другая величина равна текущей, иначе false.</returns>
		protected override bool OnEquals(Unit other)
		{
			var retVal = Type == other.Type && Value == other.Value;

			if (Type == UnitTypes.Percent || Type == UnitTypes.Absolute || Type == UnitTypes.Limit)
				return retVal;

			return retVal && Security == other.Security;
		}

		/// <summary>
		/// Сравнить величину на эквивалентность с другой.
		/// </summary>
		/// <param name="obj">Другая величина, с которой необходимо сравнивать.</param>
		/// <returns>true, если другая величина равна текущей, иначе false.</returns>
		public override bool Equals(object obj)
		{
			return base.Equals(obj);
		}

		/// <summary>
		/// Сравнить две величины на неравенство (если величины разных типов, то для сравнения будет применена конвертация).
		/// </summary>
		/// <param name="u1">Первая величина.</param>
		/// <param name="u2">Вторая величина.</param>
		/// <returns>true, если величины не равны, иначе false.</returns>
		public static bool operator !=(Unit u1, Unit u2)
		{
			return !(u1 == u2);
		}

		/// <summary>
		/// Сравнить две величины на равенство (если величины разных типов, то для сравнения будет применена конвертация).
		/// </summary>
		/// <param name="u1">Первая величина.</param>
		/// <param name="u2">Вторая величина.</param>
		/// <returns>true, если величины равны, иначе false.</returns>
		public static bool operator ==(Unit u1, Unit u2)
		{
			if (u1.IsNull())
				return u2.IsNull();

			if (u2.IsNull())
				return false;

			if (u1.Security != null && u2.Security != null && u1.Security != u2.Security)
				return false;

			if (u1.Type != u2.Type)
			{
				if (u1.Type == UnitTypes.Percent || u2.Type == UnitTypes.Percent)
					return false;

				if (u2.Type == UnitTypes.Absolute)
					u1 = u1.Convert(u2.Type);
				else
					u2 = u2.Convert(u1.Type);
			}

			return u1.Value == u2.Value;
		}

		/// <summary>
		/// Получить строковое представление.
		/// </summary>
		/// <returns>Строковое представление.</returns>
		public override string ToString()
		{
			return UnitHelper.ToString(this);
		}

		/// <summary>
		/// Проверить, является ли первая величина больше второй.
		/// </summary>
		/// <param name="u1">Первая величина.</param>
		/// <param name="u2">Вторая величина.</param>
		/// <returns>true, если первая величина больше второй, иначе false.</returns>
		public static bool operator >(Unit u1, Unit u2)
		{
			if (u1.IsNull())
				throw new ArgumentNullException("u1");

			if (u2.IsNull())
				throw new ArgumentNullException("u2");

			//if (u1.Type == UnitTypes.Limit || u2.Type == UnitTypes.Limit)
			//	throw new ArgumentException("Лимитированное значение не может участвовать в арифметических операциях.");

			if (u1.Security != null && u2.Security != null && u1.Security != u2.Security)
				throw new ArgumentException("Несовпадение инструментов {0} и {1}.".Put(u1.Security.Id, u2.Security.Id));

			if (u1.Type != u2.Type)
			{
				if (u1.Type == UnitTypes.Percent || u2.Type == UnitTypes.Percent)
					throw new ArgumentException("Проценты нельзя сравнивать с не процентами {0} и {1}.".Put(u1, u2));

				if (u2.Type == UnitTypes.Absolute)
					u1 = u1.Convert(u2.Type);
				else
					u2 = u2.Convert(u1.Type);
			}

			return u1.Value > u2.Value;
		}

		/// <summary>
		/// Проверить, является ли первая величина больше или равной второй.
		/// </summary>
		/// <param name="u1">Первая величина.</param>
		/// <param name="u2">Вторая величина.</param>
		/// <returns>true, если первая величина больше или равной второй, иначе false.</returns>
		public static bool operator >=(Unit u1, Unit u2)
		{
			return u1 == u2 || u1 > u2;
		}

		/// <summary>
		/// Проверить, является ли первая величина меньше второй.
		/// </summary>
		/// <param name="u1">Первая величина.</param>
		/// <param name="u2">Вторая величина.</param>
		/// <returns>true, если первая величина меньше второй, иначе false.</returns>
		public static bool operator <(Unit u1, Unit u2)
		{
			return u1 != u2 && !(u1 > u2);
		}

		/// <summary>
		/// Проверить, является ли первая величина меньше или равной второй.
		/// </summary>
		/// <param name="u1">Первая величина.</param>
		/// <param name="u2">Вторая величина.</param>
		/// <returns>true, если первая величина меньше или равной второй, иначе false.</returns>
		public static bool operator <=(Unit u1, Unit u2)
		{
			return !(u1 > u2);
		}

		/// <summary>
		/// Получить величину с противоположным знаком у значения <see cref="Value"/>.
		/// </summary>
		/// <param name="u">Величина.</param>
		/// <returns>Обратная величина.</returns>
		public static Unit operator -(Unit u)
		{
			if (u == null)
				throw new ArgumentNullException("u");

			return new Unit
			{
				Security = u.Security,
				Type = u.Type,
				Value = -u.Value
			};
		}

		Unit IOperable<Unit>.Add(Unit other)
		{
			return this + other;
		}

		Unit IOperable<Unit>.Subtract(Unit other)
		{
			return this - other;
		}

		Unit IOperable<Unit>.Multiply(Unit other)
		{
			return this * other;
		}

		Unit IOperable<Unit>.Divide(Unit other)
		{
			return this / other;
		}
	}

	/// <summary>
	/// Вспомогательный класс для <see cref="Unit"/>.
	/// </summary>
	public static class UnitHelper
	{
		/// <summary>
		/// Создать из <see cref="int"/> значения пипсы.
		/// </summary>
		/// <param name="value"><see cref="int"/> значение.</param>
		/// <param name="security">Инструмент, из которого берется информация по шагу цены.</param>
		/// <returns>Пипсы.</returns>
		public static Unit Pips(this int value, Security security)
		{
			return Pips((decimal)value, security);
		}

		/// <summary>
		/// Создать из <see cref="double"/> значения пипсы.
		/// </summary>
		/// <param name="value"><see cref="double"/> значение.</param>
		/// <param name="security">Инструмент, из которого берется информация по шагу цены.</param>
		/// <returns>Пипсы.</returns>
		public static Unit Pips(this double value, Security security)
		{
			return Pips((decimal)value, security);
		}

		/// <summary>
		/// Создать из <see cref="decimal"/> значения пипсы.
		/// </summary>
		/// <param name="value"><see cref="decimal"/> значение.</param>
		/// <param name="security">Инструмент, из которого берется информация по шагу цены.</param>
		/// <returns>Пипсы.</returns>
		public static Unit Pips(this decimal value, Security security)
		{
			if (security == null)
				throw new ArgumentNullException("security");

			return new Unit(value, UnitTypes.Step, security);
		}

		/// <summary>
		/// Создать из <see cref="int"/> значения пункты.
		/// </summary>
		/// <param name="value"><see cref="int"/> значение.</param>
		/// <param name="security">Инструмент, из которого берется информация по стоимости шага цены.</param>
		/// <returns>Пункты.</returns>
		public static Unit Points(this int value, Security security)
		{
			return Points((decimal)value, security);
		}

		/// <summary>
		/// Создать из <see cref="double"/> значения пункты.
		/// </summary>
		/// <param name="value"><see cref="double"/> значение.</param>
		/// <param name="security">Инструмент, из которого берется информация по стоимости шага цены.</param>
		/// <returns>Пункты.</returns>
		public static Unit Points(this double value, Security security)
		{
			return Points((decimal)value, security);
		}

		/// <summary>
		/// Создать из <see cref="decimal"/> значения пункты.
		/// </summary>
		/// <param name="value"><see cref="decimal"/> значение.</param>
		/// <param name="security">Инструмент, из которого берется информация по стоимости шага цены.</param>
		/// <returns>Пункты.</returns>
		public static Unit Points(this decimal value, Security security)
		{
			if (security == null)
				throw new ArgumentNullException("security");

			return new Unit(value, UnitTypes.Point, security);
		}

		/// <summary>
		/// Создать из <see cref="int"/> значения проценты.
		/// </summary>
		/// <param name="value"><see cref="int"/> значение.</param>
		/// <returns>Проценты.</returns>
		public static Unit Percents(this int value)
		{
			return Percents((decimal)value);
		}

		/// <summary>
		/// Создать из <see cref="double"/> значения проценты.
		/// </summary>
		/// <param name="value"><see cref="double"/> значение.</param>
		/// <returns>Проценты.</returns>
		public static Unit Percents(this double value)
		{
			return Percents((decimal)value);
		}

		/// <summary>
		/// Создать из <see cref="decimal"/> значения проценты.
		/// </summary>
		/// <param name="value"><see cref="decimal"/> значение.</param>
		/// <returns>Проценты.</returns>
		public static Unit Percents(this decimal value)
		{
			return new Unit(value, UnitTypes.Percent);
		}

		/// <summary>
		/// Пробразовать строку в <see cref="Unit"/>.
		/// </summary>
		/// <param name="str">Строковое представление <see cref="Unit"/>.</param>
		/// <param name="security">Информация по инструменту. Необходима при использовании <see cref="UnitTypes.Point"/> и <see cref="UnitTypes.Step"/>.</param>
		/// <returns>Объект <see cref="Unit"/>.</returns>
		public static Unit ToUnit(this string str, Security security = null)
		{
			if (str.IsEmpty())
				throw new ArgumentNullException("str");

			var lastSymbol = str.Last();

			if (char.IsDigit(lastSymbol))
				return new Unit(str.To<decimal>(), UnitTypes.Absolute);
			else
			{
				var value = str.Substring(0, str.Length - 1).To<decimal>();

				UnitTypes type;

				switch (lastSymbol)
				{
					case 'ш':
						type = UnitTypes.Step;
						break;
					case 'п':
						type = UnitTypes.Point;
						break;
					case '%':
						type = UnitTypes.Percent;
						break;
					case 'л':
						type = UnitTypes.Limit;
						break;
					default:
						throw new ArgumentException("Неизвестная единица измерения '{0}'.".Put(lastSymbol), "str");
				}

				return new Unit(value, type, security);
			}
		}

		/// <summary>
		/// Перевести величину в другой тип измерения.
		/// </summary>
		/// <param name="unit">Исходная величина.</param>
		/// <param name="destinationType">Тип измерения, в который необходимо перевести.</param>
		/// <returns>Сконвертированная величина.</returns>
		public static Unit Convert(this Unit unit, UnitTypes destinationType)
		{
			return unit.Convert(destinationType, unit.Security);
		}

		/// <summary>
		/// Перевести величину в другой тип измерения.
		/// </summary>
		/// <param name="unit">Исходная величина.</param>
		/// <param name="destinationType">Тип измерения, в который необходимо перевести.</param>
		/// <param name="security">Информация по инструменту. Необходима при использовании <see cref="UnitTypes.Point"/> и <see cref="UnitTypes.Step"/>.</param>
		/// <returns>Сконвертированная величина.</returns>
		public static Unit Convert(this Unit unit, UnitTypes destinationType, Security security)
		{
			if (unit == null)
				throw new ArgumentNullException("unit");

			if (unit.Type == destinationType)
				return unit.Clone();

			if (unit.Type == UnitTypes.Percent || destinationType == UnitTypes.Percent)
				throw new ArgumentException("Проценты возможно переводить только в проценты.", "unit");

			var value = (decimal)unit;

			if (destinationType == UnitTypes.Point || destinationType == UnitTypes.Step)
			{
				if (security == null)
					throw new ArgumentException("Единица измерения не может быть '{0}' так как не передана информация об инструменте.".Put(destinationType), "destinationType");

				switch (destinationType)
				{
					case UnitTypes.Point:
						var stepPrice = security.MinStepPrice;

						if (stepPrice == 0)
							throw new InvalidOperationException("Значение стоимости шага цены равно нулю.");

						value /= stepPrice;
						break;
					case UnitTypes.Step:
						value /= security.MinStepSize;
						break;
				}
			}

			return new Unit(value, destinationType, security);
		}

		internal static string ToString(Unit unit)
		{
			if (unit == null)
				throw new ArgumentNullException("unit");

			switch (unit.Type)
			{
				case UnitTypes.Percent:
					return unit.Value + "%";
				case UnitTypes.Absolute:
					return unit.Value.ToString();
				case UnitTypes.Step:
					return unit.Value + "ш";
				case UnitTypes.Point:
					return unit.Value + "п";
				case UnitTypes.Limit:
					return unit.Value + "л";
				default:
					throw new ArgumentException("Величина имеет неизвестный тип {0}.".Put(unit.Type), "unit");
			}
		}

		private static Security CheckSecurity(Unit unit, Security security)
		{
			if (unit == null)
				throw new ArgumentNullException("unit");

			if (security == null)
			{
				security = unit.Security;

				if (security == null)
					throw new ArgumentNullException("security", "Для выполнения операции необходима информация об инструменте.");
			}

			return security;
		}

		internal static decimal GetStepPrice(this Unit unit, Security security = null)
		{
			var stepPrice = CheckSecurity(unit, security).MinStepPrice;

			if (stepPrice == 0)
				throw new InvalidOperationException("Значение стоимости шага цены равно нулю.");

			return stepPrice;
		}

		internal static decimal GetStepSize(this Unit unit, Security security = null)
		{
			return CheckSecurity(unit, security).MinStepSize;
		}

		internal static decimal ShrinkPrice(this Security security, decimal price)
		{
			if (security == null)
				throw new ArgumentNullException("security");

			if (security.MinStepSize == 0)
				throw new ArgumentException("Инструмент имеет нулевой шаг цены.", "security");

			return price.Round(security.MinStepSize, security.Decimals, null);
		}

		/// <summary>
		/// Установить для величины свойство <see cref="Unit.Security"/>.
		/// </summary>
		/// <param name="unit">Величина.</param>
		/// <param name="security">Инструмент.</param>
		/// <returns>Величина.</returns>
		public static Unit SetSecurity(this Unit unit, Security security)
		{
			if (unit == null)
				throw new ArgumentNullException("unit");

			unit.Security = security;
			return unit;
		}
	}
}